iT邦幫忙

2023 iThome 鐵人賽

DAY 13
0

Table of Contents

  • 拷貝/複製物件的問題
  • 淺拷貝(Shallow copy)
  • 深拷貝
  • References

拷貝/複製物件的問題

在JavaScript中,常常會看到複製/拷貝物件的問題,那複製物件又分成深拷貝跟淺拷貝。如果沒有分清當下的複製是哪一種拷貝,假如當有個B物件被A物件複製出來,並且修改B物件的內容,可能會同時更改到A物件的內容。

淺拷貝(Shallow copy)

所謂在物件中的淺拷貝,會讓複製與被複製出來的物件屬性值指向一樣的物件來源。

JavaScript中,所有內建物件的複製方法都是淺拷貝,接下來使用Object.assign(),這個方法是拿多個物件,並且複製到某個目標物件。

但如果是下面的寫法,實際上是沒有任何複製行為的:

const contestant = {
  contestantId: 1,
  contestantName: "Alice",
  hotpotIngredients: ["Beef slices", "Tofu", "Enoki mushrooms", "Napa cabbage"],
}

const point = {
  judgeRating: 9.5
}

const contestantData = Object.assign(contestant,point)

contestantData.contestantId = 30
console.log(contestant.contestantId);//30
console.log(contestantData.contestantId);//30

可以使用一個全新的物件去裝來源物件,發現修改跟新增屬性是不受影響的:

const contestant = {
  contestantId: 1,
  contestantName: "Alice",
  hotpotIngredients: ["Beef slices", "Tofu", "Enoki mushrooms", "Napa cabbage"],
}

const contestantData = Object.assign({},contestant)

contestantData.contestantId = 30
console.log(contestant.contestantId);//1
console.log(contestantData.contestantId);//30

contestant.beveragePairing = "Jasmine tea";
console.log(contestantData.beveragePairing);//undefined

但要注意,修改hotpotIngredients的內容會同時影響原物件跟被更改的物件:

const contestant = {
  contestantId: 1,
  contestantName: "Alice",
  hotpotIngredients: ["Beef slices", "Tofu", "Enoki mushrooms", "Napa cabbage"],
}

const contestantData = Object.assign({},contestant)
contestant.hotpotIngredients[0] = null;
console.log(contestant.hotpotIngredients);// [ null, 'Tofu', 'Enoki mushrooms', 'Napa cabbage' ]
console.log(contestantData.hotpotIngredients);// [ null, 'Tofu', 'Enoki mushrooms', 'Napa cabbage' ]

坦白說,一些文章提到第一層第二層資料有點難直覺理解與解釋,所以我會把外面裝進變數的物件或陣列當作第一層,在物件中只要有用到{}[]的物件或陣列為基準來當第二層,以此類推物件中的任何更深層級的物件。

那麽淺拷貝的問題,像是在被複製的物件中第二層之後的資料不是複製過來的,只要有任何修改就會影響原物件。但以我需要的複製,是希望兩個物件之間的關係是徹底獨立的,這時候就需要使用深拷貝。

深拷貝(Deep copy)

想使用深拷貝的話,有一些第三方套件可以幫忙,或者使用JSON.stringify()轉換為JSON string,再透過JSON.parse()解析JSON string的內容,轉換一個全新物件。

把剛剛的複製方法改成JSON,並且重新輸出一次陣列,會發現兩者之間互不影響。

const contestant = {
  contestantId: 1,
  contestantName: "Alice",
  hotpotIngredients: ["Beef slices", "Tofu", "Enoki mushrooms", "Napa cabbage"],
}

const contestantData = JSON.parse(JSON.stringify(contestant));

contestant.hotpotIngredients[0] = null;
console.log(contestant.hotpotIngredients);//[ null, 'Tofu', 'Enoki mushrooms', 'Napa cabbage' ]
console.log(contestantData.hotpotIngredients);//[ 'Beef slices', 'Tofu', 'Enoki mushrooms', 'Napa cabbage' ]

Web API也有提供structuredClone() global function方法可以深拷貝,但如果要使用的話,就需要先注意程式的執行環境了。

References

  • MDN
  1. Shallow copy
  2. Object.assign()
  3. Deep copy

上一篇
〈Day12〉class的靜態、私有
下一篇
〈Day14〉JSON
系列文
廚藝不精也可以,給自己做一份Javascript小火鍋30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言